package com.neuralnoise.livejournal;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.LinkedList;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;

import com.neuralnoise.AbstractDriver;
import com.neuralnoise.LiveJournalDB;
import com.neuralnoise.foaf.core.FOAF;
import com.neuralnoise.foaf.core.FOAFReader;
import com.neuralnoise.foaf.core.Person;
import com.neuralnoise.hibernate.liveJournal.Interest;
import com.neuralnoise.hibernate.liveJournal.Journal;
import com.neuralnoise.hibernate.liveJournal.Profile;

public class LiveJournalDriver extends AbstractDriver<String> {

	private LiveJournalProperties properties;

	public LiveJournalDriver(LiveJournalProperties properties) {
		this.properties = properties;
	}

	public String getFOAF(String journal) throws Exception {
		String request = "/data/foaf";
		StringBuffer sb = new StringBuffer();
		Collection<String> lines = readLines(getWebStream(journal + ".livejournal.com", request));
		final String nl = System.getProperty("line.separator");
		for (String line : lines) {
			sb.append(line + nl);
		}
		return sb.toString();
	}

	public Collection<String> getFriends(String journal) throws Exception {
		String request = "/misc/fdata.bml?comm=1&user=" + journal;
		Collection<String> lines = readLines(getWebStream("www.livejournal.com", request));
		Collection<String> result = new LinkedList<String>();
		for (String line : lines) {
			if (line.contains("> ")) {
				result.add(line.replaceAll("^.> ", ""));
			}
		}
		return result;
	}
	
	public Collection<Interest> getInterests(String journal) throws Exception {
		String request = "/misc/interestdata.bml?user=" + journal;
		Collection<String> lines = readLines(getWebStream("www.livejournal.com", request));
		Collection<Interest> result = new LinkedList<Interest>();
		for (String line : lines) {
			if (!line.startsWith("# ") && !line.startsWith("! ")) {
				int s1 = line.indexOf(' ');
				if (s1 > 0) {
					int s2 = line.indexOf(' ', s1 + 1);
					String sintid = line.substring(0, s1);
					String sintcount = line.substring(s1 + 1, s2);
					String interest = line.substring(s2 + 1, line.length());
					Interest i = new Interest(Integer.valueOf(sintid), Integer.valueOf(sintcount), interest);
					result.add(i);
				}
			}
		}
		return result;
	}

	public Collection<String> getRSS(String journal) throws Exception {
		String request = "/data/rss?auth=digest";
		return readLines(getWebStream(journal + ".livejournal.com", request));
	}

	private Collection<String> readLines(InputStreamReader reader) throws IOException {
		Collection<String> result = new LinkedList<String>();
		if (reader != null) {
			BufferedReader br = new BufferedReader(reader);
			String line = br.readLine();
			while (line != null) {
				result.add(line);
				line = br.readLine();
			}
		}
		return result;
	}

	private Collection<String> readLines(InputStream stream) throws IOException {
		return readLines((stream != null ? new InputStreamReader(stream) : null));
	}

	private InputStream getWebStream(String shost, String srequest) throws Exception {
		HttpHost host = new HttpHost(shost, 80, "http");
		DefaultHttpClient client = new DefaultHttpClient();

		AuthScope scope = new AuthScope(shost, 80);
		Credentials creds = new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword());
		client.getCredentialsProvider().setCredentials(scope, creds);

		AuthCache authCache = new BasicAuthCache();
		DigestScheme digestAuth = new DigestScheme();
		digestAuth.overrideParamter("realm", "some realm");
		digestAuth.overrideParamter("nonce", "whatever");
		authCache.put(host, digestAuth);

		BasicHttpContext localcontext = new BasicHttpContext();
		localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

		HttpGet request = new HttpGet(srequest);
		request.setHeader("User-Agent", "http://www.uniba.it; pasquale.minervini@uniba.it");
		HttpResponse response = null;
		try {
			response = client.execute(host, request, localcontext);
		} catch (Exception e) {
			//
		}
		
		if (response == null)
			return null;
		
		HttpEntity entity = response.getEntity();
		return entity.getContent();
	}

	@Override
	public boolean hasUserData(String journal) {
		boolean ret = false;
		Profile profile = LiveJournalDB.getProfile(journal);
		if (profile != null) {
			ret = true;
		}
		return ret;
	}

	@Override
	public void addUserData(String _journal) throws Exception {
		//Journal journal = 
		LiveJournalDB.toJournal(_journal);
		String foaf = getFOAF(_journal);
		LiveJournalDB.addProfile(_journal, foaf);
		Collection<Interest> interests = getInterests(_journal);
		LiveJournalDB.addInterests(_journal, interests);
		Collection<String> friends = getFriends(_journal);
		LiveJournalDB.addFriendsOf(_journal, friends);
	}
	
	@Override
	public Collection<String> getConnections(String _journal) throws Exception {
		Collection<Journal> _friends = LiveJournalDB.getFriendsOf(_journal);
		SortedSet<String> friends = new TreeSet<String>();
		for (Journal _friend : _friends) {
			friends.add(_friend.getId());
		}
		return friends;
	}

	@Override
	public Person toPerson(String journal) throws Exception {
		if (!hasUserData(journal)) {
			addUserData(journal);
		}
		Person person = null;
		Profile profile = LiveJournalDB.getProfile(journal);
		if (profile != null) {
			String foaf = profile.getFoaf();
			
			InputStream stream = IOUtils.toInputStream(foaf);
			FOAFReader reader =  FOAFReader.newInstanceFromStream(stream, null);
			
			FOAF f = reader.read();
			if (f.searchAllPeople().size() > 0)
				person = f.searchAllPeople().iterator().next();
		}
		return person;
	}
}
